﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace ArgusPCLib.IO
{
	public class CRC32Stream : StreamWrapper
	{
		CRC32 crc;

		public CRC32Stream(Stream baseStream)
			: base(baseStream)
		{
			this.crc = ArgusPCLib.CRC32.CreateTable();
			this.AllowSeeking = false;
		}

		public int CRC32 { get { return this.crc.CurrentCRC; } }

		/// <summary>
		/// Warning: Seeking will mess up the resulting CRC32 value.
		/// </summary>
		public bool AllowSeeking { get; set; }

		public override long Position
		{
			get { return base.Position; }
			set
			{
				if (this.AllowSeeking == false)
					throw new InvalidOperationException("CRC32Stream.AllowSeeking is false");
				base.Position = value;
			}
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			if (this.AllowSeeking == false)
				throw new InvalidOperationException("CRC32Stream.AllowSeeking is false");
			return base.Seek(offset, origin);
		}

		public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
		{
			int RetVal = await base.ReadAsync(buffer, offset, count, cancellationToken);
			this.crc.Add(buffer, offset, count);
			return RetVal;
		}

		public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
		{
			await base.WriteAsync(buffer, offset, count, cancellationToken);
			this.crc.Add(buffer, offset, count);
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			count = base.Read(buffer, offset, count);
			this.crc.Add(buffer, offset, count);
			return count;
		}

		public override int ReadByte()
		{
			int b = base.ReadByte();
			if (b > -1)
				this.crc.Add((byte)b);
			return b;
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			this.crc.Add(buffer, offset, count);
			base.Write(buffer, offset, count);
		}

		public override void WriteByte(byte value)
		{
			this.crc.Add(value);
			base.WriteByte(value);
		}
	}
}
